package com.cy.db.common.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Aspect 注解描述的类为spring aop中的一个切面类型,此类型可以定义为
 * 1)切入点(PointCut)方法(可以是多个):要进行功能扩展的一些点
 * 2)通知(Advice)方法(可以是多个):封装了扩展功能的一些方法(在切入点方法之前或者之后要执行的方法)
 */
@Aspect
@Slf4j
@Component
public class SysLogAspect {
    /**
     * @Pointcut 注解描述的方法为切入点方法,注解中定义的内容为切入点表达式(可以有多种形式)
     * 1)bean(bean名称)切入点表达式,这个表达式中的名字为spring容器中管理的一个bean的名字
     * 2)bean表达式是一种粗粒度的切入点表达式,这种表达式定义的切入点表示bean中的所有方法都是
     * 将来要切入扩展功能的一些方法(目标方法)
     * 在当前应用中,sysUserServiceImpl这个名字对应的bean中所有的方法的集合为切入点
     */
    @Pointcut("bean(sysUserServiceImpl)")
    public void logPointCut(){}//方法中不写任何内容,只是切入点表达式的载体

    /**
     *  @Around 注解描述的方法为一个通知方法,这个通知方法我们称之为环绕通知,可以在
     *  目标方法执行之前或之后做服务增益.在环绕通知方法我们可以自己控制目标方法的调用
     * @param jp 连接点对象,此对象分装了要执行的目标方法信息
     * @return 目标的执行结果
     * @throws  执行目标方法过程中出现的异常
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint jp) throws Throwable {
        long t1 = System.currentTimeMillis();
        try {
            Object result = jp.proceed();//执行你的目标方法
            long t2 = System.currentTimeMillis();
            log.info("目标方法执行时长:{}",t2-t1);
            return result;
        }catch (Throwable e){
            log.error("目标方法执行过程中出现了问题,具体问题为:",e.getMessage());
            throw e;
        }
    }
}
